-- store_mgr.lua

local sformat       = string.format

Store = class()
local prop = property(Store)
prop:accessor("id", nil)
prop:accessor("name", nil)
prop:accessor("codec", nil)
prop:accessor("driver", nil)
prop:accessor("filename", nil)
prop:accessor("sheets", {})
prop:accessor("caches", {})

function Store:__init(name)
    self.name = name
end

function Store:load(filename)
    local driver = smdb.create()
    if not driver.open(filename) then
        print("store:load() failed, filename:", filename)
        return false
    end
    local codec = json.jsoncodec()
    driver.set_codec(codec)
    self.filename = filename
    self.driver = driver
    self.codec = codec
    --读取数据
    self:load_smdb(driver)
    return true
end

function Store:load_smdb(driver)
    local key, value = driver.first()
    while value do
        self:read_kv(key, value)
        key, value = driver.next()
    end
end

function Store:flush()
    self.driver.flush(self.filename)
end

function Store:put(key, value, sheet)
    local real_val = self:encode(sheet, key, value)
    local ok = self.driver.put(sformat("%s:%s", sheet, key), real_val)
    if not ok then
        print("[Store][put] put fail!", sheet, key, value)
    end
    self:flush()
    return ok
end

function Store:del(key, sheet)
    self.sheets[sheet][tostring(key)] = nil
    self.driver.del(sformat("%s:%s", sheet, key))
end

function Store:clear_sheet(sheet, values)
    for key,_ in pairs(values) do
        self:del(key, sheet)
    end
    self.sheets[sheet] = nil
    self:flush()
end

function Store:close()
    self.driver.close()
end

function Store:get(sheet, key)
    local sheet_tab = self.sheets[sheet]
    if not sheet_tab then
        print("Store get not sheet_tab sheet:"..sheet)
        return
    end
    if not sheet_tab[key] then
        if sheet_tab[tostring(key)] then
            return sheet_tab[tostring(key)]
        end
        return
    end
    return sheet_tab[key]
end

function Store:getTables()
    local data = table.tkvarray(self.sheets)
    table.sort(data, function(a, b)
        return a[1] < b[1]
    end)
    return data
end

function Store:read_kv(key, value)
    local sheet_tab, sheet_key, sheet = self:read_sheet(key)
    sheet_tab[sheet_key] = value
    if sheet == "game_world" then
        self.id = value.world_id
    end
end

function Store:read_sheet(key)
    local sheet = "golbal"
    local pos = key:find(":")
    if pos then
        sheet = key:sub(1, pos - 1)
        key = key:sub(pos + 1)
    end
    if not self.sheets[sheet] then
        self.sheets[sheet] = {}
    end
    return self.sheets[sheet], key, sheet
end

local data_funcs = {
    player = { resume = "resume_player" },
    player_task = { resume = "resume_player_task" },
    world_storage = { format = "format_world_storage", resume = "resume_world_storage" },
    world_building = { format = "format_world_building", resume = "resume_world_building" },
    storage_childs = { format = "format_storage_childs", resume = "resume_storage_childs" },
    world_build_unit = { format = "format_world_build_unit", resume = "resume_world_build_unit" },
    player_utility = { format = "format_player_utility", resume = "resume_player_utility" },
}

function Store:getCache(sheet, key)
    if not self.caches[sheet] then
        return {}
    end
    if not self.caches[sheet][key] then
        return {}
    end 
    return self.caches[sheet][key]
end

function Store:decode(sheet, key, value)
    local copyvalue = table.deepcopy(value)
    local caches = self.caches[sheet]
    if not caches then
        self.caches[sheet] = {}
        caches = self.caches[sheet]
    end
    if caches[key] then
        return caches[key]
    end
    if data_funcs[sheet] then
        local func = self[data_funcs[sheet].format]
        if func then
            func(self, copyvalue)
        end
    end
    local jsonvalue = json.pretty(copyvalue)
    caches[key] = string.split(jsonvalue, "\n")
    return caches[key]
end

function Store:encode(sheet, key, value)
    if data_funcs[sheet] then
        local func = self[data_funcs[sheet].resume]
        if func then
            local raw = self:get(sheet, key)
            func(self, value, raw)
        end
    end
    return value
end

--需要特殊处理的数据，需要单独处理
-----------------------------------------------
function Store:resume_player(value, raw)
    value.tutorial = raw.tutorial
    value.tutorial_now = raw.tutorial_now
end

function Store:format_world_build_unit(value)
    for _, unit in pairs(value.units or {}) do
        unit.detail = nil
    end
end

function Store:format_world_storage(value)
    value.store_thumb = nil
end

function Store:format_world_building(value)
    for id, _ in pairs(value.buildings or {}) do
        value.buildings[id].transform = {}
    end
end

function Store:format_storage_childs(value)
    for key, val in pairs(value.childs or {}) do
        val.thumb = nil
    end
end

function Store:resume_player_task(value, raw)
    value.story = raw.story
end

function Store:resume_world_storage(value, raw)
    value.store_thumb = raw.store_thumb
end

function Store:resume_world_build_unit(value, raw)
    for id, unit in pairs(value.units or {}) do
        unit.detail = raw.units[id].detail
    end
end

function Store:resume_world_building(value, raw)
    for id, unit in pairs(value.buildings or {}) do
        unit.detail = raw.buildings[id].detail
    end
end

function Store:resume_storage_childs(value, raw)
    for id, val in pairs(value.childs or {}) do
        val.thumb = raw.childs[id].thumb
    end
end

function Store:format_player_utility(value)
    value.photos = nil
end

function Store:resume_player_utility(value, raw)
    value.photos = raw.photos
end